/**
 * @fileOverview
 * @author iNahoo
 * @since 2019/12/1.
 */
const {createImageData} = require('canvas');
const BaseBitMap = require('./BaseBitMap');
const Matrix = require('./Matrix');

const Sobel = {
    x: new Matrix(
        [
            -1, -2, -1,
            0, 0, 0,
            1, 2, 1
        ],
        3, 3
    ),
    y: new Matrix(
        [
            -1, 0, 1,
            -2, 0, 2,
            -1, 0, 1
        ],
        3, 3
    ),

    sobelProcess(m) {
        const w = m.w;
        const h = m.h;
        const bm = m.bitmap;
        const len = bm.length;
        const grayMatrix = new Uint8ClampedArray(w * h);

        let q;

        function limit(v) {
            if (v < 0) {
                return 0;
            } else if (v >= len) {
                return len - 1;
            }
            return v;
        }

        function compare(x, y) {
            return Math.floor(Math.sqrt(x * x + y * y));
        }

        function onePixel(i, sobel_matrix) {
            const b = sobel_matrix.bitmap;
            let sum = 0;
            q = i - 1 - w;
            sum += bm[limit(q)] * b[0];
            sum += bm[limit(q + 1)] * b[1];
            sum += bm[limit(q + 2)] * b[2];

            q = i - 1;
            sum += bm[limit(q)] * b[3];
            sum += bm[limit(q + 1)] * b[4];
            sum += bm[limit(q + 2)] * b[5];

            q = i - 1 + w;
            sum += bm[limit(q)] * b[6];
            sum += bm[limit(q + 1)] * b[7];
            sum += bm[limit(q + 2)] * b[8];

            return sum;
        }

        m.traversal((v, i) => {
            grayMatrix[i] = compare(
                onePixel(i, Sobel.x),
                onePixel(i, Sobel.y),
            )
        });

        return new Matrix(grayMatrix, w, h);
    }
};


class BitMapUtil {

    /**
     * @param matrix {Matrix}
     * @param t
     */
    static transferBitMatrix(matrix, t = 128) {
        const grayMatrix = new Uint8ClampedArray(matrix.w * matrix.h);
        matrix.traversal((v, i) => {
            grayMatrix[i] = v > t ? 1 : 0;
        });
        return new Matrix(grayMatrix, matrix.w, matrix.h);
    }

    /**
     * @param matrix {Matrix}
     */
    static getBitMatrixImageData(matrix) {
        const gu8ar = new Uint8ClampedArray(matrix.w * matrix.h * 4);
        let i = 0, j = 0, v;
        while (i < matrix.bitmap.length) {
            v = matrix.bitmap[i];
            gu8ar[j] = v * 255;
            gu8ar[j + 1] = v * 255;
            gu8ar[j + 2] = v * 255;
            gu8ar[j + 3] = 255;
            i++;
            j += 4
        }

        return createImageData(gu8ar, matrix.w, matrix.h);
    }

    static getGrayMatrix(bitmap, w, h) {
        const grayMatrix = new Uint8ClampedArray(w * h);

        let i_matrix = 0;
        let i_image = 0;
        let count = 0;
        let sum = 0;

        while (i_image < bitmap.length) {
            if (count !== 3) {
                sum += bitmap[i_image];
            }
            i_image++;
            count++;

            if (count === 4) {
                grayMatrix[i_matrix] = sum / 3;
                count = 0;
                sum = 0;
                i_matrix++;
            }
        }

        return new Matrix(grayMatrix, w, h);
    }

    static getGrayImageData(matrix) {
        const gu8ar = new Uint8ClampedArray(matrix.w * matrix.h * 4);
        let i = 0, j = 0, v;
        while (i < matrix.bitmap.length) {
            v = matrix.bitmap[i];
            gu8ar[j] = v;
            gu8ar[j + 1] = v;
            gu8ar[j + 2] = v;
            gu8ar[j + 3] = 255;
            i++;
            j += 4
        }

        return createImageData(gu8ar, matrix.w, matrix.h);
    }

}

module.exports = {
    BitMapUtil,
    Sobel,
};

